package dal

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"pulsar_study/domain/event"
	"pulsar_study/infra"
	"time"

	"github.com/google/wire"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

var DomainEventSet = wire.NewSet(wire.Struct(new(DomainEventDal), "*"))

const (
	EventStateUnsent = iota
	EventStateSent
)

type DomainEventDal struct {
	DB    *gorm.DB
	Redis *redis.Client
}

func (d *DomainEventDal) Save(ctx context.Context, e event.DomainEvent) (uint, error) {
	db := infra.GetDB(ctx, d.DB)
	store := d.toDomainEventStore(e)
	res := db.Create(store)
	return store.ID, res.Error
}
func (d *DomainEventDal) UpdateSendState(ctx context.Context, id uint, state int) error {
	db := infra.GetDB(ctx, d.DB)
	result := db.Model(&event.DomainEventStore{}).Where("id = ?", id).Update("event_state", state)
	return result.Error
}

func (d *DomainEventDal) MarkEventProcessed(ctx context.Context, topic, eventID string) (bool, error) {
	hasher := sha256.New()
	hasher.Write([]byte(topic))
	topicHash := hex.EncodeToString(hasher.Sum(nil))

	key := fmt.Sprintf("%s:%s", topicHash, eventID)

	// set key with ttl 3 days
	const ttl = 24 * 3 * time.Hour

	return d.Redis.SetNX(ctx, key, "1", ttl).Result()
}

func (d *DomainEventDal) toDomainEventStore(e event.DomainEvent) *event.DomainEventStore {
	return &event.DomainEventStore{
		EventID:    e.ID(),
		EntityID:   e.GetEntityID(),
		EventTime:  e.OccurredOn(),
		EventBody:  e.String(),
		EventType:  e.GetEventName(),
		EventState: EventStateUnsent,
	}
}
